package com.jamal2362.apktool.util.sai;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

public class Installer {
    private PackageInstaller packageInstaller;
    private Context mContext;
	private String packageName;

	public Installer(Context ctx) {
		mContext = ctx.getApplicationContext();
		packageInstaller =  mContext.getPackageManager().getPackageInstaller();
		packageName = null;
	}

    private static class InstallParams {
        PackageInstaller.SessionParams sessionParams;
    }

    public int installApk(File[] files) {
        HashMap<String, Long> nameSizeMap = new HashMap<>();
        HashMap<String, String> filenameToPathMap = new HashMap<>();
        long totalSize = 0;
        int sessionId = 0;
        try {
            for (File file : files) {
				nameSizeMap.put(file.getName(), file.length());
				filenameToPathMap.put(file.getName(), file.getAbsolutePath());
				totalSize += file.length();
				if (packageName != null)
					continue;
				try {
					PackageManager pm = mContext.getPackageManager();
					PackageInfo packageInfo = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_ACTIVITIES);
					String pn = packageInfo.packageName;
					if (pn != null)
						packageName = pn;
				} catch (Exception e) {}
			}
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
        final InstallParams installParams = makeInstallParams(totalSize);
        try {
            sessionId = runInstallCreate(installParams);
            for (Map.Entry<String,Long> entry : nameSizeMap.entrySet()) {
                runInstallWrite(entry.getValue(), sessionId, entry.getKey(), filenameToPathMap.get(entry.getKey()));
            }
            doCommitSession(sessionId, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sessionId;
    }

    private int runInstallCreate(InstallParams installParams) {
        return doCreateSession(installParams.sessionParams);
    }

    private int doCreateSession(PackageInstaller.SessionParams params) {
        int sessionId = 0 ;
        try {
            sessionId = packageInstaller.createSession(params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sessionId;
    }

    private int runInstallWrite(long size, int sessionId , String splitName , String path) {
        return doWriteSession(sessionId, path, size, splitName, true);
    }

    private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,  boolean logSuccess) {
        if ("-".equals(inPath)) {
            inPath = null;
        } else if (inPath != null) {
            final File file = new File(inPath);
            if (file.isFile()) {
                sizeBytes = file.length();
            }
        }
        PackageInstaller.Session session = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            session = packageInstaller.openSession(sessionId);
            if (inPath != null) {
                in = new FileInputStream(inPath);
            }
            out = session.openWrite(splitName, 0, sizeBytes);
            int total = 0;
            byte[] buffer = new byte[65536];
            int c;
            while ((c = in.read(buffer)) != -1) {
                total += c;
                out.write(buffer, 0, c);
            }
            session.fsync(out);
            return PackageInstaller.STATUS_SUCCESS;
        } catch (Exception e) {
            return PackageInstaller.STATUS_FAILURE;
        } finally {
            try {
                out.close();
                in.close();
                session.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private int doCommitSession(int sessionId, boolean logSuccess) {
        PackageInstaller.Session session = null;
        try {
            try {
                session = packageInstaller.openSession(sessionId);
            } catch (Exception e) {
                e.printStackTrace();
            }
            Intent callbackIntent = new Intent(mContext, InstallService.class);
			callbackIntent.putExtra("packageName", packageName);
            PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, callbackIntent, 0);
            session.commit(pendingIntent.getIntentSender());
            session.close();
            return 1;
        } finally {
            session.close();
        }
    }

    private InstallParams makeInstallParams(long totalSize) {
        final PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        final InstallParams params = new InstallParams();
        params.sessionParams = sessionParams;
        sessionParams.setSize(totalSize);
        return params;
    }
}
